#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Edge{
    int src, dest, weight;
};

struct Graph{
    int V, E;

    struct Edge* edge;
};

struct Graph* createGraph(int V, int E){

    struct Graph* graph = (struct Graph*) malloc( sizeof(struct Graph) );
    graph->V = V;
    graph->E = E;

    graph->edge = (struct Edge*) malloc( graph->E * sizeof( struct Edge ) );

    return graph;
}

struct subset{
    int parent;
    int rank;
};

int find(struct subset subsets[], int i){
    if (subsets[i].parent != i)
        subsets[i].parent = find(subsets, subsets[i].parent);

    return subsets[i].parent;
}


void Union(struct subset subsets[], int x, int y){
    int xroot = find(subsets, x);
    int yroot = find(subsets, y);

    if (subsets[xroot].rank < subsets[yroot].rank)
        subsets[xroot].parent = yroot;
    else if (subsets[xroot].rank > subsets[yroot].rank)
        subsets[yroot].parent = xroot;
        
    else{
        subsets[yroot].parent = xroot;
        subsets[xroot].rank++;
    }
}

void KruskalMST(struct Graph* graph){

    int V = graph->V;
    struct Edge result[V]; 
    int e = 0;  
    int i = 0;  
    int finalWeight=0;

    struct subset *subsets =
        (struct subset*) malloc( V * sizeof(struct subset) );

    int v;
    for ( v = 0; v < V; ++v){
        subsets[v].parent = v;
        subsets[v].rank = 0;
    }

    while (e < V -2){
        struct Edge next_edge = graph->edge[i++];

        int x = find(subsets, next_edge.src);
        int y = find(subsets, next_edge.dest);
        
        if (x != y){
            result[e++] = next_edge;
            Union(subsets, x, y);
        }
    }

    printf("MST\n");
    for (i = 0; i < e; ++i){
        finalWeight = finalWeight + result[i].weight;
        printf("%d -- %d == %d\n", result[i].src+1, result[i].dest+1,result[i].weight);
    }
    printf("Final weight = %d \n", finalWeight);
}

int main()
{
// -----------------------------------------------------------------------
    int V,E,heapSize=0,startVertices,endVertices,weight, totallyWeight=0 ;
    int x, i=0,j, temp=0 , now;

    FILE *myFile;
    FILE *fp;
    fpos_t dlugosc, MAXdlugosc;

    if ((myFile=fopen("c:\\mst5.in", "rb"))==NULL || (fp=fopen("c:\\mst5.in", "rb"))==NULL ) {
    printf ("B³¹d otwarcia pliku: %s!\n", "c:\\tekst.txt");
    return 1;
    }
    fseek (fp, 0, SEEK_END); /* ustawiamy wskaŸnik na koniec pliku */
    fgetpos (fp, &dlugosc);
    MAXdlugosc=dlugosc+1;

    //read file into array
    int firstArray[2]; // array of numbers of edges and vertices

    if (myFile == NULL){
        printf("Error Reading File\n");
        exit (0);
    }
    for (i = 0; i <= 1 ; i++){
        fscanf(myFile, "%d", &firstArray[i] );
    }

    V = firstArray[0]+1;
    E = firstArray[1]+1;
    int numberArray[E*3 + 1];


    for (i = 1 ; i < firstArray[1]*3+1; i++){
            fscanf(myFile, "%d", &numberArray[i] );
    }
        fclose(myFile);


    struct Graph* graph = createGraph(V, E);
    for (i = 1, heapSize =0; i < E*3+1;){

        temp=i;
        startVertices =numberArray[i]-1;
        endVertices =numberArray[i+1]-1;
        weight = numberArray[i+2];

        graph->edge[heapSize].src = startVertices; /*Insert in the last place*/
        graph->edge[heapSize].dest = endVertices;
        graph->edge[heapSize].weight = weight;
        /*Adjust its position*/

        now = heapSize;
        if(heapSize > 0){
            while(graph->edge[now-1].weight > weight && now>0){
                    graph->edge[now].weight = graph->edge[now-1].weight;
                    graph->edge[now].src = graph->edge[now-1].src;
                    graph->edge[now].dest = graph->edge[now-1].dest;
                    now =now-1;
            }
        }
        graph->edge[now].src = startVertices;
        graph->edge[now].dest = endVertices;
        graph->edge[now].weight = weight;

        i=temp+3;
        heapSize++;
    }

    KruskalMST(graph);

    return 0;
}
